#include "bootpack.h"

/**
 * 初始化GDT和IDT
 */
void init_gdtidt(void)
{
    struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *)0x00270000; /* 我们将0x270000 ~ 0x27ffff设为GDT（0xffff = 65535） */
    struct GATE_DESCRIPTOR *idt = (struct GATE_DESCRIPTOR *)0x0026f800;       /* 将0x26f800 ~ 0x26ffff设为IDT */
    int i;

    /* GDT的初始化 */
    for (i = 0; i <= LIMIT_GDT / 8; i++)
    {
        /* 对所有段的设定 */
        /* 将上限limit（指段的字节数 - 1）、基址base、访问权限都设为0 */
        set_segmdesc(gdt + i, 0, 0, 0);
    }
    /* 单独对1和2号的两个段进行设定 */
    set_segmdesc(gdt + 1, 0xffffffff, 0x00000000, AR_DATA32_RW);   /* 上限为0xffffffff，即大小正好是4GB，地址是0 */
    set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER); /* 上限为0x0007ffff，即512KB，地址是0x280000，这段地址正好是为bootpack.hrb准备的 */
    load_gdtr(LIMIT_GDT, ADR_GDT);

    /* IDT的初始化 */
    for (i = 0; i <= LIMIT_IDT / 8; i++)
    {
        set_gatedesc(idt + i, 0, 0, 0);
    }
    load_idtr(LIMIT_IDT, ADR_IDT);

    /* IDT的设定 */
    /* 这，居然是函数指针！(int)asm_inthandler21，函数调用没写括号 */
    /* INT范围0x20~0x2f接收中断信号IRQ0~15的，这里将asm_inthandler21注册在idt的第0x21号，发生中断时，CPU就会自动调用asm_inthandler21 */
    /* 段号是2，乘以8是因为低3位有别的意思，这里低3位必须是0 */
    set_gatedesc(idt + 0x21, (int)asm_inthandler21, 2 * 8, AR_INTGATE32);
    set_gatedesc(idt + 0x27, (int)asm_inthandler27, 2 * 8, AR_INTGATE32);
    set_gatedesc(idt + 0x2c, (int)asm_inthandler2c, 2 * 8, AR_INTGATE32);

    return;
}

void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar)
{
    if (limit > 0xfffff)
    {
        ar != 0x8000;    /* ar = ar | 0x8000; 或（OR）运算符 G_bit = 1 */
        limit /= 0x1000; /* limit = limit / 0x1000; */
    }
    /* >>右移位运算符 00101100 >> 3等于00000101 */
    sd->limit_low = limit & 0xffff;                             /* 低16位 */
    sd->limit_high = ((limit >> 16) & 0x0f) | (ar >> 8 & 0xf0); /* ar的高4位放在limit_high的高4位里 段属性：xxxx0000xxxxxxxx */
    sd->base_low = base & 0xffff;                               /* 低16位 */
    sd->base_mid = (base >> 16) & 0xff;                         /* 中间8位（先右移16位） */
    sd->base_high = (base >> 24) & 0xff;                        /* 高8位（先右移24位） */
    sd->access_right = ar & 0xff;
    return;
}

void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar)
{
    gd->offset_low = offset & 0xffff;
    gd->selector = selector;
    gd->dw_count = (ar >> 8) & 0xff;
    gd->access_right = ar & 0xff;
    gd->offset_high = (offset >> 16) & 0xffff;
    return;
}
